#include "st7796_mipi.h"

#if USE_LCD_PANEL_ST7796_MIPI

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "lvgl/src/lv_core/lv_refr.h"
#include "lvgl/src/lv_core/lv_disp.h"
#include "lvgl/src/lv_hal/lv_hal_tick.h"
#include "crane_lcdc.h"
#include "crane_lcd_mipi.h"
#include "crane_lcd_mipi_dsi.h"
#include "../common/utils.h"
#include "../common/lv_pm.h"
#include "../../board.h"
#include "lv_conf.h"

#define UNLOCK_DELAY         10
#define LCD_COLOR_DEPTH_BYTE (LV_COLOR_DEPTH / 8)
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))

#define OPM035B_GPIO_LCD_POWR_EN          GPIO33
#define OPM035B_GPIO_LCD_LEVEL_CON_EN     GPIO34

static lv_disp_drv_t * lcd_disp_drv = NULL;
static lcd_context g_lcd_ctx;
extern int cur_load_tp;
unsigned short cur_lcd_id;
#define ID_TABLE_END 0
unsigned st7796_mipi_id_table[] = {
    0x7796,
    ID_TABLE_END,
};
static struct s_dsi_cmd_desc st7796_xz_init_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x11}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x36,0x90}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3a,0x55}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0xc3}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x96}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xb0,0x80}},
//  {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xb1,0x80,0x10}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xb4,0x01}},
//  {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xb5,0x60,0x60,0x00,0x04}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,4,{0xb6,0x20,0x02,0x3b}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xb7,0xc6}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xb9,0x02,0xe0}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xc0,0x80,0x25}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc1,0x09}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc2,0xa7}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc5,0x19}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,9,{0xE8,0x40,0x8a,0x00,0x00,
                                                0x29,0x19,0xa5,0x33}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,15,{0xE0,0xd2,0x05,0x08,0x06,
                                                 0x05,0x02,0x2a,0x44,0x46,
                                                 0x39,0x15,0x15,0x2d,0x32}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,15,{0xE1,0x96,0x08,0x0c,0x09,
                                                 0x09,0x25,0x2e,0x43,0x42,
                                                 0x35,0x11,0x11,0x28,0x2e}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x35,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0x44,0x00,0x20}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x3c}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x69}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x21}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,1,{0x29}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,5,{0x2a,0x00,0x00,0x01,0x3f}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,5,{0x2b,0x00,0x00,0x01,0xdf}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,10,1,{0x2c}},
};

static struct s_dsi_cmd_desc st7796_init_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x11}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x36,0x90}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x3a,0x55}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0xc3}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x96}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xb4,0x01}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xb7,0xc6}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xB9,0x02,0xE0}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0xc0,0x80,0x16}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc1,0x19}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc2,0xa7}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xc5,0x19}},//0x16


    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,9,{0xE8,0x40,0x8a,0x00,0x00,
                                                0x29,0x19,0xa5,0x33}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,15,{0xE0,0xF0,0x07,0x0D,0x04,
                                                 0x05,0x14,0x36,0x54,0x4C,
                                                 0x38,0x13,0x14,0x2E,0x34}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,15,{0xE1,0xF0,0x10,0x14,0x0E,
                                                 0x0C,0x08,0x35,0x44,0x4C,
                                                 0x26,0x10,0x12,0x2c,0x32}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0x35,0x00}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,3,{0x44,0x00,0x20}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x3c}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,2,{0xf0,0x69}},

    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x21}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,1,{0x29}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,5,{0x2a,0x00,0x00,0x01,0x3f}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,UNLOCK_DELAY,5,{0x2b,0x00,0x00,0x01,0xdf}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,10,1,{0x2c}},
};

static struct s_dsi_cmd_desc st7796_set_cmds[] = {
    {DSI_SET_MAX_PKT_SIZE, DSI_LP_MODE, UNLOCK_DELAY, 1, {0x3}},
};


static struct s_dsi_cmd_desc st7796_read_id_cmds[] = {
    {DSI_GENERIC_READ1, DSI_LP_MODE, UNLOCK_DELAY, 1, {0xd3}},
};


static struct s_dsi_cmd_desc st7796_display_on_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x11}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,20,1,{0x29}},
};

static struct s_dsi_cmd_desc st7796_display_off_cmds[] = {
    {DSI_DCS_LWRITE,DSI_LP_MODE,50,1,{0x28}},
    {DSI_DCS_LWRITE,DSI_LP_MODE,120,1,{0x10}},
};

const static struct s_mipi_info lcd_st7796_mipi_info = {
    320, /*width*/
    480, /*height*/
    30,//132, /*hfp*/
    30,//156, /*hbp*/
    10,//12, /*hsync*/
    20,//24, /*vfp*/
    20,//36, /*vbp*/
    6,//4, /*vsync*/
    60, /*fps*/
    DSI_MODE_CMD, /*work_mode*/
    DSI_INPUT_DATA_RGB_MODE_565, /*rgb_mode*/
    1, /*lane_number*/
    400000, /*phy_freq: KHz*/ //should be
    0, /*split_enable*/
    1, /*eotp_enable*/

    DSI_BURST_MODE_NON_BURST_SYNC_PULSE, /*burst_mode*/

    /*following force to 0*/
    1, /*te_enable*/
    0, /*vsync_pol*/
    0, /*te_pol*/
    0, /*te_mode*/

    /*The following fields need not be set by panel*/
    0,
};

static uint8_t suspend_flag = 0;
static uint32_t st7796_last_flush_ticks = 0;
static void st7796_mipi_suspend(void *arg)
{
    struct crane_panel_t *p = arg;
    cplog_printf("st7796_mipi_suspend\n");

    /*since disp_refr can be changed by other register,
     *so if st7796 suspend need use lcd_disp_drv instead of lv_refr_vdb_is_flushing()
     *refer to lv_disp_refr_task() and lv_refr_vdb_flush()*/
    st7796_last_flush_ticks = lv_tick_get();
    if(lcd_disp_drv && lcd_disp_drv->buffer) {
        // wait flushing finish~~
        while(lcd_disp_drv->buffer->flushing && (lv_tick_elaps(st7796_last_flush_ticks)<500))
            ;
    }

    lcdc_stop(&g_lcd_ctx);
    lcd_dsi_after_refresh();
    p->panel_onoff(0);
    lcd_mipi_uninit();
    suspend_flag = 1;
}

static void st7796_mipi_resume(void *arg)
{
    struct crane_panel_t *p = arg;
    cplog_printf("st7796_mipi_resume\n");
    lcdc_resume();
    p->panel_onoff(1);
    lcd_dsi_before_refresh();

    suspend_flag = 0;
    lv_obj_invalidate(lv_disp_get_scr_act(NULL));
    lv_refr_now(_lv_refr_get_disp_refreshing());
    st7796_last_flush_ticks = lv_tick_get();
    if(lcd_disp_drv && lcd_disp_drv->buffer) {
        // wait flushing finish~~
        while(lcd_disp_drv->buffer->flushing && (lv_tick_elaps(st7796_last_flush_ticks)<500))
            ;
    }
}

static void st7796_mipi_panel_invalid(uint32_t start_x,
                                  uint32_t start_y,  uint32_t end_x, uint32_t end_y)
{
    struct s_dsi_cmd_desc invalid_cmds[3];

    lcd_dsi_update_mipi_info(end_x-start_x + 1, end_y-start_y + 1);

    invalid_cmds[0].cmd_type = DSI_DCS_LWRITE;
    invalid_cmds[0].lp = DSI_HS_MODE;
    invalid_cmds[0].delay = 0;
    invalid_cmds[0].length = 5;
    invalid_cmds[0].data[0] = 0x2A;
    invalid_cmds[0].data[1] = (start_x >> 8) & 0xFF;
    invalid_cmds[0].data[2] = (start_x) & 0xFF;
    invalid_cmds[0].data[3] = (end_x >> 8) & 0xFF;
    invalid_cmds[0].data[4] = (end_x) & 0xFF;

    invalid_cmds[1].cmd_type = DSI_DCS_LWRITE;
    invalid_cmds[1].lp = DSI_HS_MODE;
    invalid_cmds[1].delay = 0;
    invalid_cmds[1].length = 5;
    invalid_cmds[1].data[0] = 0x2B;
    invalid_cmds[1].data[1] = (start_y >> 8) & 0xFF;
    invalid_cmds[1].data[2] = (start_y) & 0xFF;
    invalid_cmds[1].data[3] = (end_y >> 8) & 0xFF;
    invalid_cmds[1].data[4] = (end_y) & 0xFF;

    invalid_cmds[2].cmd_type = DSI_DCS_SWRITE;
    invalid_cmds[2].lp = DSI_HS_MODE;
    invalid_cmds[2].delay = 0;
    invalid_cmds[2].length = 1;
    invalid_cmds[2].data[0] = 0x2c;

    lcd_dsi_write_cmds(invalid_cmds, ARR_SIZE(invalid_cmds));
}

static int match_id(unsigned id, unsigned *id_table)
{
    int found = 0;
    unsigned *p = id_table;

    while (*p) {
        if (id == *p) {
            found = 1;
            break;
        }
        p++;
    }

    return (found == 1) ? 1 : 0;
}

static int check_times = 0;
void esd_check_delay_us(unsigned int time)
{
    unsigned int i,j,k;

    for(i=0;i< time;i++)
    {
        for(j=0;j<100;j++)
        {
            k=0;
        }
    }
}

static struct s_dsi_cmd_desc st7796_read_esd_cmds[] = {
    {DSI_GENERIC_READ1, DSI_LP_MODE, UNLOCK_DELAY, 1, {0x0a}},
};

static void check_st7796_esd(void)
{
    struct s_dsi_rx_buf dbuf;
    int id[5];

    lcd_dsi_write_cmds(st7796_set_cmds, ARR_SIZE(st7796_set_cmds));
    lcd_dsi_read_cmds(&dbuf, st7796_read_esd_cmds,ARR_SIZE(st7796_read_esd_cmds));

    id[0] = dbuf.data[0];
    id[1] = dbuf.data[1];
    id[2] = dbuf.data[2];
    id[3] = dbuf.data[3];
    id[4] = dbuf.data[4];
    uart_printf("st7796_mipi_read_esd: data 0 - 4 is 0x%x, 0x%x, 0x%x, 0x%x, 0x%x \n",id[0],id[1],id[2],id[3],id[4]);
}

void esd_check_task(void)
{
    int times = 0;

    check_times++;
    if(suspend_flag){
        return;
    }
//  esd_last_flush_ticks = lv_tick_get();
    if(lcd_disp_drv==NULL)
    {
        return;
    }
//  cplog_printf("enter check_esd\n");
    if(check_times == 40){
        while(lcd_disp_drv->buffer->flushing) {
            if(times>100000){
                printf("check_esd time out\n");
                break;
            }
            esd_check_delay_us(1);
            times++;
        }
        check_st7796_esd();
        check_times = 0;
    }
}

extern void ctp_bl_ts_checkid(void);
static int st7796_mipi_read_id(unsigned *pid)
{
    struct s_dsi_rx_buf dbuf;

    int id[5];

    lcd_dsi_write_cmds(st7796_set_cmds, ARR_SIZE(st7796_set_cmds));
    lcd_dsi_read_cmds(&dbuf, st7796_read_id_cmds,ARR_SIZE(st7796_read_id_cmds));

    id[0] = dbuf.data[0];
    id[1] = dbuf.data[1];
    id[2] = dbuf.data[2];
    id[3] = dbuf.data[3];
    id[4] = dbuf.data[4];
    cplog_printf("st7796_mipi_read_id: data 0 - 4 is 0x%x, 0x%x, 0x%x, 0x%x, 0x%x \n",
         id[0],id[1],id[2],id[3],id[4]);

    cur_lcd_id = (unsigned int)(id[2] | (id[1]<<8));//id[0];
    if(cur_lcd_id == 0x9488){
        *pid = cur_lcd_id;
    }else{
        *pid = 0x7796;
    }
    cplog_printf("*pid =%x\n",*pid);
    ctp_bl_ts_checkid();
//  cplog_printf("tp =%d\n",cur_load_tp);
    return 0;
}

__attribute__ ((unused)) static int panel_detect_readid(void)
{
    unsigned id = 0;
    if (st7796_mipi_read_id(&id) < 0) {
        cplog_printf("panel read id failed\n");
        goto err;
    }

    if (match_id(id, st7796_mipi_id_table) == 0) {
        cplog_printf("unknown panel id = 0x%x\n", id);
        goto err;
    }

    cplog_printf("Found LCD panel st7796-mipi, id: 0x%x\n", id);
    cplog_printf("panel detect by readid ok\n");

    return 0;
err:
    cplog_printf("panel detect by readid failed\n");
    return -1;
}

typedef int (*panel_detect_fn_t)(void);

static panel_detect_fn_t detect_fn[] = {
    panel_detect_readid,
};

static int panel_detect(void)
{
    int cnt = ARRAY_SIZE(detect_fn);
    int i, ret;

    for (i = 0; i < cnt; i++) {
        ret = detect_fn[i]();
        if (ret == 0) {
            return 0;
        }
    }

    return -1;
}
extern void lcdc_reset_panel_level(int level);
static void st7796_mipi_onoff(int on)
{
    if (on) {
        lcdc_reset_panel();
        if(cur_load_tp){
            lcd_dsi_write_cmds(st7796_xz_init_cmds, ARR_SIZE(st7796_xz_init_cmds));
        }else{
            lcd_dsi_write_cmds(st7796_init_cmds, ARR_SIZE(st7796_init_cmds));
        }
    //lcd_dsi_write_cmds(st7796_display_on_cmds, ARR_SIZE(st7796_display_on_cmds));
    } else {   /* off */
        lcd_dsi_write_cmds(st7796_display_off_cmds, ARR_SIZE(st7796_display_off_cmds));
        lcdc_reset_panel_level(0);
    }
}

extern void lcd_dsi_reset(void);
static int st7796_mipi_probe(unsigned lcd_clk)
{
    static int inited = 0;
    lv_pm_info_t pm_info;

    gpio_set_direction(OPM035B_GPIO_LCD_POWR_EN, GPIO_OUT);
    gpio_set_direction(OPM035B_GPIO_LCD_LEVEL_CON_EN, GPIO_OUT);

    gpio_output_set(OPM035B_GPIO_LCD_LEVEL_CON_EN,0);
    gpio_output_set(OPM035B_GPIO_LCD_POWR_EN,0);
    Ningbo_Ldo_8_set(0);

    Ningbo_Ldo_1_set_2_8();
    Ningbo_Ldo_1_set(1);

    lcd_mipi_init(lcd_clk, 0, &lcd_st7796_mipi_info);
    lcd_mipi_reset();

    if(inited) {
        return 0;
    }

    int silent_reset = startup_silent_reset();
    if(!silent_reset) {
        lcdc_reset_panel();
    }

    if (panel_detect() < 0) {
        return -1;
    }

    //   lcdc_reset_panel();
    if(cur_load_tp){
        lcd_dsi_write_cmds(st7796_xz_init_cmds, ARR_SIZE(st7796_xz_init_cmds));
    }else{
        lcd_dsi_write_cmds(st7796_init_cmds, ARR_SIZE(st7796_init_cmds));
    }

    memset(&g_lcd_ctx, 0, sizeof(lcd_context));
    g_lcd_ctx.bg_color = 0x0000ff; /*bg color : red*/
    g_lcd_ctx.alpha_mode = LCD_ALPHA_MODE_NORMAL;
    g_lcd_ctx.output_config.format = MIPI_FORMAT_CMD;

    pm_info.suspend = st7796_mipi_suspend;
    pm_info.resume = st7796_mipi_resume;
    pm_info.data = &st7796_mipi;
    pm_info.part = LV_PM_PART_DISPLAY;
    lv_pm_register(&pm_info);
    inited = 1;

    lcd_dsi_before_refresh();
    return 0;
}

static void dump_vdb2sd(lv_color_t * color_p, uint32_t buf_len)
{
    static int frame_count = 0;
    char ui_frame[32] = "d:/ui_frame";
    INT32 fd;

    sprintf(ui_frame, "d:/ui_frame_%d.raw", frame_count++);
    cplog_printf("dump %s\r\n", ui_frame);
    fd = FS_Open((PCSTR)ui_frame,	FS_O_CREAT | FS_O_TRUNC | FS_O_WRONLY, 0);
    FS_Write(fd,(UINT8 *)color_p, buf_len);
    FS_Close(fd);

    return;
}

//static lv_color_t color_p_backup[320*480] = {0};
extern int Rgb565ConvertBmp(lv_color_t * color_p,int width,int height);
static unsigned int last_flush_tick = 0;
/*refer to lv_port_disp_template.c, when lcdc_irq come, set lv_disp_flush_ready()*/
static void st7796_mipi_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    //cplog_printf("st7796_mipi_flush: [%d, %d] , [%d, %d]\n", area->x1, area->y1, area->x2, area->y2);
    unsigned int flush_tick = 0;
    lcd_disp_drv = disp_drv;
    if(suspend_flag == 1) {
        lv_disp_flush_ready(disp_drv);
        return;
    }

 //   if (memcmp(&color_p_backup, color_p, sizeof(color_p_backup)) == 0) {
 //       lv_disp_flush_ready(disp_drv);
 //       return;
 //   } else {
//        memcpy(&color_p_backup, color_p, sizeof(color_p_backup));
//    }
    uint32_t width, height, stride;
    unsigned buf_len;

    width = area->x2 - area->x1 + 1;
    height = area->y2 - area->y1 + 1;
//  Rgb565ConvertBmp(color_p,width,height);
#if (LV_COLOR_DEPTH == 16)
    stride = width * LCD_COLOR_DEPTH_BYTE;
#else
    cplog_printf("lv config is not 16 bits color depth !!!!!!!!!!!\n");
    return;
#endif
//  for(int i=0;i<320*480;i++){
//      color_p[i].ch.red = 0x1f;
//      color_p[i].ch.blue = 0;
//      color_p[i].ch.green = 0;
//  }
    cplog_printf("st7796_mipi_flush:x1:%d, x2:%d, y1:%d, y2:%d, stride:%d\n", area->x1, area->x2, area->y1, area->y2, stride);
    flush_tick = lv_tick_get();
    last_flush_tick = flush_tick;
    buf_len = stride * height;
    flush_cache((unsigned long)color_p, buf_len);
    g_lcd_ctx.layer_config_osd1.buf1 = (void *)color_p;
    g_lcd_ctx.layer_config_osd1.format = LCD_FORMAT_RGB565;
    g_lcd_ctx.layer_config_osd1.layer_enable = 1;
    g_lcd_ctx.layer_config_osd1.stride = stride;
    g_lcd_ctx.layer_config_osd1.x = 0;
    g_lcd_ctx.layer_config_osd1.y = 0;
    g_lcd_ctx.layer_config_osd1.width = width;
    g_lcd_ctx.layer_config_osd1.height = height;
    g_lcd_ctx.layer_config_osd1.alpha = 0xff;

    g_lcd_ctx.wb_config.wb_enable = 0;
    g_lcd_ctx.layer_config_img.layer_enable = 0;

    lcdc_update_output_setting(&g_lcd_ctx.output_config, width, height);
    lcdc_update_mipi_output_setting(&g_lcd_ctx.output_config, &lcd_st7796_mipi_info);
    st7796_mipi_panel_invalid(area->x1, area->y1, area->x2, area->y2);
    lcd_dsi_before_refresh();
    lcdc_sync(&g_lcd_ctx, 0); /* irq mode */
//    lv_disp_flush_ready(disp_drv);
}

struct crane_panel_t st7796_mipi = {
    .probe = st7796_mipi_probe, /* lcd_init() in board_evb.c also need change */
    .readid = st7796_mipi_read_id,
    .panel_onoff = st7796_mipi_onoff,
    .flush = st7796_mipi_flush,
};

#endif
